using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace DuToanT2.Models.DomainBase
{
    public abstract class EntityBase
    {

        private bool selected;
        private List<BrokenRule> brokenRules;
        private BrokenRuleMessages brokenRuleMessages;

        protected EntityBase()
        {
            this.selected = false;
            this.brokenRules = new List<BrokenRule>();
            //this.brokenRuleMessages = this.GetBrokenRuleMessages();
        }

        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int ID { get; set; }

        [NotMapped]
        public bool IsSelected {
            get { return this.selected; }
            set { this.selected = value; }
        }

        #region Validation and Broken Rules

        //protected abstract void Validate();

        //protected abstract BrokenRuleMessages GetBrokenRuleMessages();

        protected List<BrokenRule> BrokenRules
        {
            get { return this.brokenRules; }
        }

        public ReadOnlyCollection<BrokenRule> GetBrokenRules()
        {
            //this.Validate();
            return this.brokenRules.AsReadOnly();
        }

        protected void AddBrokenRule(string messageKey)
        {
            this.brokenRules.Add(new BrokenRule(messageKey,
                this.brokenRuleMessages.GetRuleDescription(messageKey)));
        }

        #endregion

        #region Equality Tests

        /// <summary>
        /// Determines whether the specified entity is equal to the 
        /// current instance.
        /// </summary>
        /// <param name="entity">An <see cref="System.Object"/> that 
        /// will be compared to the current instance.</param>
        /// <returns>True if the passed in entity is equal to the 
        /// current instance.</returns>
        public override bool Equals(object entity)
        {
            return entity != null
                && entity is EntityBase
                && this == (EntityBase)entity;
        }

        /// <summary>
        /// Operator overload for determining equality.
        /// </summary>
        /// <param name="base1">The first instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <param name="base2">The second instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <returns>True if equal.</returns>
        public static bool operator ==(EntityBase base1, 
            EntityBase base2)
        {
            // check for both null (cast to object or recursive loop)
            if ((object)base1 == null && (object)base2 == null)
            {
                return true;
            }

            // check for either of them == to null
            if ((object)base1 == null || (object)base2 == null)
            {
                return false;
            }

            if (base1.ID != base2.ID)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// Operator overload for determining inequality.
        /// </summary>
        /// <param name="base1">The first instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <param name="base2">The second instance of an 
        /// <see cref="EntityBase"/>.</param>
        /// <returns>True if not equal.</returns>
        public static bool operator !=(EntityBase base1, 
            EntityBase base2)
        {
            return (!(base1 == base2));
        }

        /// <summary>
        /// Serves as a hash function for this type.
        /// </summary>
        /// <returns>A hash code for the current Key 
        /// property.</returns>
        public override int GetHashCode()
        {
            if (this.ID != null)
            {
                return this.ID.GetHashCode();
            }
            else
            {
                return 0;
            }
        }

        #endregion
    }
}
